﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using MongoServices.Tests.TestHelpers;
using MongoServices.Tests.Stubs;
using MongoDB.Driver;
using System.Configuration;
using MongoDB.Bson;

namespace MongoServices.Tests.ConfigurationTests
{
	public class MongoUrlProviderTests : TestBase
	{
		private const string SECOND_URL = "mongodb://localhost/MongoServicesTests2";
		private const string THIRD_URL = "mongodb://localhost/MongoServicesTests3";

		protected ReadWriteRepositoryTestModelSimpleStub Repository { get; private set; }
		protected MongoCollection<TestModelSimple> CollectionDefaultDatabase { get; private set; }
		protected MongoCollection<TestModelSimple> CollectionSecondDatabase { get; private set; }
		protected MongoCollection<TestModelSimple> CollectionThirdDatabase { get; private set; }

		protected Func<MongoUrl> getSecondUrl = () => {
			return new MongoUrl(SECOND_URL);
		};

		protected Func<MongoUrl> getThirdUrl = () => {
			return new MongoUrl(THIRD_URL);
		};

		public MongoUrlProviderTests()
		{
			Setup();
		}

		private void Setup()
		{
			Repository = new ReadWriteRepositoryTestModelSimpleStub();
			CollectionDefaultDatabase = MongoDatabase.Create(ConfigurationManager.ConnectionStrings["MongoServiceConnectionString"].ConnectionString)
														.GetCollection<TestModelSimple>(COLLECTION_NAME_TEST_MODEL_SIMPLE);
			CollectionSecondDatabase = MongoDatabase.Create(SECOND_URL).GetCollection<TestModelSimple>(COLLECTION_NAME_TEST_MODEL_SIMPLE);
			CollectionThirdDatabase = MongoDatabase.Create(THIRD_URL).GetCollection<TestModelSimple>(COLLECTION_NAME_TEST_MODEL_SIMPLE);
		}

		public override void Dispose()
		{
			base.Dispose();
			MongoServicesConfig.SetMongoUrlProvider(MongoServicesMongoUrlProvider.GetMongoUrl);
			ReadWriteRepositoryTestModelSimpleStub.SetMongoUrlProvider(null);

			if (CollectionSecondDatabase.Database.CollectionExists(COLLECTION_NAME_TEST_MODEL_SIMPLE))
			{
				CollectionSecondDatabase.Database.DropCollection(COLLECTION_NAME_TEST_MODEL_SIMPLE);
			}

			if (CollectionThirdDatabase.Database.CollectionExists(COLLECTION_NAME_TEST_MODEL_SIMPLE))
			{
				CollectionThirdDatabase.Database.DropCollection(COLLECTION_NAME_TEST_MODEL_SIMPLE);
			}
		}
	}

	public class WhenNoSpecificProviderIsProvided : MongoUrlProviderTests
	{
		[Fact]
		public void DataIsSaveToTheMongoServiceConnectionStringDatabase()
		{
			var model = new TestModelSimple { Id = ObjectId.GenerateNewId(), TestField = "TestData" };

			Repository.Save(model);

			var results = CollectionDefaultDatabase.FindAllAs<TestModelSimple>();

			Assert.Equal(1, results.Count());
			Assert.Equal(model, results.First(), new TestModelSimpleWithIdEqualityComparer());
		}
	}

	public class WhenGlobalUrlProviderIsProvided : MongoUrlProviderTests
	{
		[Fact]
		public void DataIsSavedToTheAppropriateDatabase()
		{
			MongoServicesConfig.SetMongoUrlProvider(getSecondUrl);

			var model = new TestModelSimple { Id = ObjectId.GenerateNewId(), TestField = "TestData" };

			Repository.Save(model);

			var results = CollectionSecondDatabase.FindAllAs<TestModelSimple>();

			Assert.Equal(1, results.Count());
			Assert.Equal(model, results.First(), new TestModelSimpleWithIdEqualityComparer());
		}
	}

	public class WhenRepositoryUrlProviderIsProvided : MongoUrlProviderTests
	{
		[Fact]
		public void DataIsSavedToTheAppropriateDatabase()
		{
			ReadWriteRepositoryTestModelSimpleStub.SetMongoUrlProvider(getThirdUrl);

			var model = new TestModelSimple { Id = ObjectId.GenerateNewId(), TestField = "TestData" };

			Repository.Save(model);

			var results = CollectionThirdDatabase.FindAllAs<TestModelSimple>();

			Assert.Equal(1, results.Count());
			Assert.Equal(model, results.First(), new TestModelSimpleWithIdEqualityComparer());
		}

		[Fact]
		public void DataIsNotSavedToTheGlobalUrlProviderDatabase()
		{
			MongoServicesConfig.SetMongoUrlProvider(getSecondUrl);
			ReadWriteRepositoryTestModelSimpleStub.SetMongoUrlProvider(getThirdUrl);

			var model = new TestModelSimple { Id = ObjectId.GenerateNewId(), TestField = "TestData" };

			Repository.Save(model);

			var results = CollectionSecondDatabase.FindAllAs<TestModelSimple>();

			Assert.Equal(0, results.Count());
		}
	}
}
